 /*      smol.y
 *
 *      Copyright 2009-2010 virpool <virpool@ukrpost.ua>
 *
 *      This program is free software; you can redistribute it and/or modify
 *      it under the terms of the GNU General Public License as published by
 *      the Free Software Foundation; either version 2 of the License, or
 *      (at your option) any later version.
 *
 *      This program is distributed in the hope that it will be useful,
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *      GNU General Public License for more details.
 *
 *      You should have received a copy of the GNU General Public License
 *      along with this program; if not, write to the Free Software
 *      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 *      MA 02110-1301, USA.
 */

%{
#include <iostream>
#include <cstdio>
#include <sys/types.h>
#include <signal.h>
#include <list>
#include <string.h>
#include <readline/readline.h>
#include <readline/history.h>
#include "../vm/SClassObject.h"
#include "../vm/SClassInteger.h"
#include "../vm/SClassFloat.h"
#include "../vm/SClassBoolean.h"
#include "../vm/SClassString.h"
#include "../vm/SClassArray.h"
#include "../vm/SClassHash.h"
#include "../vm/SClassFile.h"
#include "../vm/SVMachine.h"

//#define DEBUG_YACC_MODE

extern "C" 
{
	void yyerror(char*);
	int yylex(void);
	int yy_scan_string(const char *);
	void yy_delete_buffer(int buf);
	void yy_switch_to_buffer(int new_buffer);
	unsigned int ind;
	extern FILE *yyin;
	int main_buf = 0;
}

list<std::string> buf; // special for operations
list<std::string> pbuf; // special for operations with parameters
list<std::string> stdout_buf; // special for very long output (puts, put etc.). analog of std::stringbuilder

list<void*> garbage;

int array_indx = -1;
bool is_array_operation = false;
bool is_ok_array = false;

bool is_hash_operation = false;

void test_for_array();

std::string hash_key;

S_ARG_TYPES arg_type; // it's needed for: new (Type, value); 
S_ARG_TYPES arg_type_arr; // for arrays

std::string create_string(char *str);
void make_float(char *s);
void id_parse_prepare(num_act na);

bool is_spec_op_flag = false;

int val_int;
float val_float;
std::string val_string;
bool val_bool;

bool is_value;

e_actions expr_act;

bool is_this;

bool is_array;
bool is_array_dyn;
S_ARG_TYPES is_array_type;
unsigned int is_array_index; 

unsigned int op_param_cnt = 0;

bool is_oper_with_params_now = false;

bool is_get_object = false;

/* for expressions */

SObject *left_side;
SObject *right_side;

/* */
void add_integer();

bool test_parent();

bool is_expr_now = false;
bool is_expr_error = false;

bool is_for_init = false;
bool is_for_step = false;

bool is_new_method = false;

bool expr_val_bool;

int sc_lvl = 0;

typedef struct 
{
	bool if_alter;
	bool if_expr;
} s_loop;

s_loop loops[255];
unsigned short loop_cnt = 0;

s_command *commands[255];

int inin = 0, noend = 0;

#define CHECK bool ifok = false; if (!test_parent() && ! loops[loop_cnt-1].if_alter && ! loops[loop_cnt-1].if_expr) \
				{ commands[sc_lvl-1]->child.push_back(s); ifok = true; } \
				else if (test_parent() && loop_cnt && ((! loops[loop_cnt-1].if_expr && loops[loop_cnt-1].if_alter) || is_new_method)) \
				{ commands[sc_lvl-1]->alt_child.push_back(s); ifok = true; }\
				else if (test_parent() && loop_cnt && loops[loop_cnt-1].if_expr) \
				{ commands[sc_lvl-1]->if_expr_child.push_back(s); ifok = true; }\
				if (!ifok) commands[sc_lvl-1]->child.push_back(s);
						
#define CHECKEX s->parent = commands[sc_lvl-1]; CHECK

%}

%token VAR NEW IN FOR FOREACH WHILE IF ELIF ELSE NUM FNUM HNUM ID BTRUE BFALSE PUT PUTS INPUT EXIT VALUE THIS METHOD DELETE BREAK SOME_TEXT
%token STRING INTEGER FLOAT BOOLEAN ARRAY HASH CFILE DBL_SK
%left ADD_ASSIGN SUB_ASSIGN DIV_ASSIGN MUL_ASSIGN MOD_ASSIGN XOR_ASSIGN OR_ASSIGN AND_ASSIGN RIGHT_OP LEFT_OP INC_OP DEC_OP AND_OP OR_OP GE_OP LE_OP EQ_OP NE_OP AND OR NOT XOR
%left '+' '-' '<' '^' '&' 
%left '*' '/' '!'
%left UMINUS 


%%
program: /*EMPTY*/
	| program sentence
	| program error { yyerrok; yyclearin; loop_cnt = 0; }
	;

sentence:
	var_asign ';'
	| expression ';'
	| operation_s ';'
	| put_s ';'
	| puts_s ';'
	| input_s ';'
	| for_s
	| while_s
	| if_s 
	| method_s
	| break_s ';'
	| EXIT { exit(0); }
	;

	
var_asign_simple:
	VAR var_asign_simple_list	
	;
	
var_asign_simple_list:
	var_asign_simple_item
	| var_asign_simple_list ',' var_asign_simple_item	
	;
	
var_asign_simple_item:
	ID '=' id_dotlist
	{
		s_command *s = new s_command;
		s->comm = s_new;
		s->is_var = true;
		s->is_obj = false;
		s->obj_id = (char*)$1;
		s->buf = buf;
		s->value = true; // for variant : var a = b; in right side: object.
		s->arg_type = arg_type;
		s->arg_type_arr = arg_type_arr;
		s->is_value = is_value;
		s->val_int = val_int;
		s->val_float = val_float;
		s->val_string = val_string;
		s->val_bool = val_bool;
		s->is_oper_with_params_now = false;
		s->is_expr_now = false;
		s->is_array_operation = false;
		s->is_array = false;
		s->is_hash_operation = false;
		if (sc_lvl == 0)
		{
			SVMachine::GetInstance()->AddCommand(s);
			SVMachine::GetInstance()->Execute();
		}
		else
		{
			if (!is_for_init)
			{
				CHECKEX
			}
			else
			{
				commands[sc_lvl-1]->for_init = s;
			}
		}
		buf.clear();
	}
	| ID '=' var_asign_simple_value
	{
		s_command *s = new s_command;
		s->comm = s_new;
		s->is_var = true;
		s->is_obj = false;
		s->obj_id = (char*)$1;
		s->buf = buf;
		s->value = false; // for variant : var a = 3; in right side: no object.
		s->arg_type = arg_type;
		s->arg_type_arr = arg_type_arr;
		s->is_value = is_value;
		s->val_int = val_int;
		s->val_float = val_float;
		s->val_string = val_string;
		s->val_bool = val_bool;
		s->is_oper_with_params_now = false;
		s->is_expr_now = false;
		s->is_array_operation = false;
		s->is_array = false;
		s->is_hash_operation = false;
		if (sc_lvl == 0)
		{
			SVMachine::GetInstance()->AddCommand(s);
			SVMachine::GetInstance()->Execute();
		}
		else
		{
			if (!is_for_init)
			{
				CHECKEX
			}
			else
			{
				commands[sc_lvl-1]->for_init = s;
			}
		}
		buf.clear();
	}
	;
	
var_asign_simple_value:
	number { arg_type = S_INT; is_value = true; }
	| HNUM { arg_type = S_INT; is_value = true; }
	| FNUM { arg_type = S_FLOAT; is_value = true; make_float((char*)$1); }
	| BOOL { arg_type = S_BOOL; is_value = true;}
	| SOME_TEXT { arg_type = S_STRING; val_string = create_string((char*)$1); is_value = true; }
	;
	
var_asign:
	var_asign_simple
	| VAR var_list
	| id_dotlist '=' NEW '(' var_declar ')' 
		{
			s_command *s = new s_command;
			s->comm = s_new;
			s->is_var = false;
			s->is_obj = false;
			s->buf = buf;
			s->arg_type = arg_type;
			s->arg_type_arr = arg_type_arr;
			s->is_value = is_value;
			s->val_int = val_int;
			s->val_float = val_float;
			s->val_string = val_string;
			s->val_bool = val_bool;
			s->is_oper_with_params_now = false;
			s->is_expr_now = false;
			s->is_array_operation = false;
			s->is_array = false;
			s->is_hash_operation = false;
			if (sc_lvl == 0)
			{
				SVMachine::GetInstance()->AddCommand(s);
				SVMachine::GetInstance()->Execute();
			}
			else
			{
				if (!is_for_init)
				{
					CHECKEX
				}
				else
				{
					commands[sc_lvl-1]->for_init = s;
				}
			}
			buf.clear();
		}
	| id_dotlist '=' NEW
		{
			s_command *s = new s_command;
			s->comm = s_new;
			s->is_var = false;
			s->is_obj = true;
			s->buf = buf;
			s->arg_type = arg_type;
			s->is_value = is_value;
			s->val_int = val_int;
			s->val_float = val_float;
			s->val_string = val_string;
			s->val_bool = val_bool;
			s->is_oper_with_params_now = false;
			s->is_expr_now = false;
			s->is_array_operation = false;
			s->is_array = false;
			s->is_hash_operation = false;
			if (sc_lvl == 0)
			{
				SVMachine::GetInstance()->AddCommand(s);
				SVMachine::GetInstance()->Execute();
			}
			else
			{
				if (!is_for_init)
				{
					CHECKEX
				}
				else
				{
					commands[sc_lvl-1]->for_init = s;
				}
			}
			buf.clear();
		}				
	;
	
var_list:
	var_listitem
	| var_listitem ',' var_list
	;
	
var_listitem:
	ID
	| var_id
	;

var_id:
	ID '=' NEW '(' var_declar ')' 
		{
			s_command *s = new s_command;
			s->comm = s_new;
			s->is_var = true;
			s->is_obj = false;
			s->buf = buf;
			s->obj_id = (char*)$1;
			s->arg_type = arg_type;
			s->arg_type_arr = arg_type_arr;
			s->is_value = is_value;
			s->val_int = val_int;
			s->val_float = val_float;
			s->val_string = val_string;
			s->val_bool = val_bool;
			s->is_oper_with_params_now = false;
			s->is_expr_now = false;
			s->is_array_operation = false;
			s->is_array = false;
			s->is_hash_operation = false;
			if (sc_lvl == 0)
			{
				SVMachine::GetInstance()->AddCommand(s);
				SVMachine::GetInstance()->Execute();
			}
			else
			{
				if (!is_for_init)
				{
					CHECKEX
				}
				else
				{
					commands[sc_lvl-1]->for_init = s;
				}
			}
			buf.clear();
		}
	| ID '=' NEW 
		{ 
			s_command *s = new s_command;
			s->comm = s_new;
			s->is_var = true;
			s->is_obj = true;
			s->buf = buf;
			s->obj_id = (char*)$1;
			s->arg_type = arg_type;
			s->is_value = is_value;
			s->val_int = val_int;
			s->val_float = val_float;
			s->val_string = val_string;
			s->val_bool = val_bool;
			s->is_oper_with_params_now = false;
			s->is_expr_now = false;
			s->is_array_operation = false;
			s->is_array = false;
			s->is_hash_operation = false;
			if (sc_lvl == 0)
			{
				SVMachine::GetInstance()->AddCommand(s);
				SVMachine::GetInstance()->Execute();
			}
			else
			{
				if (!is_for_init)
				{
					CHECKEX
				}
				else
				{
					commands[sc_lvl-1]->for_init = s;
				}
			}
			buf.clear();
		}
	;
	
var_declar:
	type_associate
	| type 
	;
	
type_associate:
	STRING ',' SOME_TEXT { arg_type = S_STRING; val_string = create_string((char*)$3); is_value = true; }
	| INTEGER ',' number { arg_type = S_INT; is_value = true; }
	| INTEGER ',' HNUM { arg_type = S_INT; is_value = true; }
	| FLOAT ',' FNUM { arg_type = S_FLOAT; is_value = true; make_float((char*)$3); }
	| BOOLEAN ',' BOOL { arg_type = S_BOOL; is_value = true;}
	| ARRAY ',' array_type ',' DBL_SK { arg_type = S_ARRAY; is_value = false; }
	| ARRAY ',' array_type ',' '[' NUM ']' { arg_type = S_ARRAY; val_int = atoi((char*)$6); is_value = true;  }
	| HASH { arg_type = S_HASH; is_value = true; }
	| CFILE { arg_type = S_FILE; is_value = true; }
	;

expression:
	'%' expr_left assign_type expr_right
	{
		s_command *s = commands[--sc_lvl];
		if (!s)
			cerr << "epic fail!\n";
		if (sc_lvl == 0)
		{
			SVMachine::GetInstance()->AddCommand(s);
			SVMachine::GetInstance()->Execute();
		}
		else
		{
			CHECKEX
		}
		buf.clear();
		stdout_buf.clear();
		is_expr_now = false;
	}
	;
	
assign_type_eq:
	'=' { 
		if (sc_lvl)
			commands[sc_lvl-1]->expr_act = e_eq;
	}		
	;

assign_type:
	assign_type_eq
	| ADD_ASSIGN
	{
		if (sc_lvl)
			commands[sc_lvl-1]->expr_act = e_add;
	}
	| SUB_ASSIGN
	{
		if (sc_lvl)
			commands[sc_lvl-1]->expr_act = e_sub;
	}
	| MUL_ASSIGN
	{
		if (sc_lvl)
			commands[sc_lvl-1]->expr_act = e_mul;
	}
	| DIV_ASSIGN
	{
		if (sc_lvl)
			commands[sc_lvl-1]->expr_act = e_div;
	}
	| MOD_ASSIGN
	{
		if (sc_lvl)
			commands[sc_lvl-1]->expr_act = e_mod;
	}
	| XOR_ASSIGN
	{
		if (sc_lvl)
			commands[sc_lvl-1]->expr_act = e_xor;
	}
	| OR_ASSIGN
	{
		if (sc_lvl)
			commands[sc_lvl-1]->expr_act = e_or;
	}
	| AND_ASSIGN
	{
		if (sc_lvl)
			commands[sc_lvl-1]->expr_act = e_and;
	}
	;

expr_left:
	expr_left_item
	//| expr_left_item '=' 
	;
	
expr_left_item:
	id_dotlist
		{
			s_command *s = new s_command;
			s->comm = s_expr;
			s->buf = buf;
			s->is_oper_with_params_now = false;
			s->is_array_operation = false;
			s->is_array = false;
			s->is_hash_operation = false;
			commands[sc_lvl++] = s;
			buf.clear();
			s->is_expr_now = true;
		}
	| id_dotlist '[' number ']'
		{
			s_command *s = new s_command;
			s->comm = s_expr;
			s->buf = buf;
			s->is_oper_with_params_now = false;
			s->is_array_operation = false;
			s->is_array = true;
			s->is_hash_operation = false;
			commands[sc_lvl++] = s;
			buf.clear();
			s->is_expr_now = true;
			s->is_array_dyn = false;
			s->is_array_index = atoi((char*)$3);
			s->is_expr_now = true;
		}
	| id_dotlist DBL_SK
		{
			s_command *s = new s_command;
			s->comm = s_expr;
			s->buf = buf;
			s->is_oper_with_params_now = false;
			s->is_array_operation = false;
			s->is_array = true;
			s->is_hash_operation = false;
			commands[sc_lvl++] = s;
			buf.clear();
			s->is_expr_now = true;
			s->is_array_dyn = true;
			s->is_array_index = -1;
			s->is_expr_now = true;
		}
	| VALUE
		{
			s_command *s = new s_command;
			s->comm = s_expr;
			s->value = true;
			s->is_put_single_out = true;
			s->out = "";
			s->buf = buf;
			s->arg_type = S_VALUE;
			s->is_value = is_value;
			s->val_int = val_int;
			s->val_float = val_float;
			s->val_string = val_string;
			s->val_bool = val_bool;
			s->is_oper_with_params_now = false;
			s->is_array_operation = false;
			s->is_array = false;
			s->is_hash_operation = false;
			commands[sc_lvl++] = s;
			buf.clear();
			s->is_expr_now = true;
		}		
	;

id_dotlist:
	ID { std::string s = (char*)$1; buf.push_back(s); }
	| id_dotlist '.' ID { std::string s = (char*)$3; buf.push_back(s); }
	;

expr_right:
	arg_item
	| expr_right AND_OP expr_right
		{
			commands[sc_lvl - 1]->expr_stack.push_back(s_land);
		}
	| expr_right AND expr_right
		{
			commands[sc_lvl - 1]->expr_stack.push_back(s_land);
		}	
	| expr_right OR_OP expr_right
		{
			commands[sc_lvl - 1]->expr_stack.push_back(s_lor);
		}
	| expr_right OR expr_right
		{
			commands[sc_lvl - 1]->expr_stack.push_back(s_lor);
		}
	| expr_right RIGHT_OP expr_right
		{
			commands[sc_lvl - 1]->expr_stack.push_back(s_shr);
		}
	| expr_right LEFT_OP expr_right	
		{
			commands[sc_lvl - 1]->expr_stack.push_back(s_shl);
		}
	| expr_right GE_OP expr_right
		{
			commands[sc_lvl - 1]->expr_stack.push_back(s_ge);
		}
	| expr_right LE_OP expr_right
		{
			commands[sc_lvl - 1]->expr_stack.push_back(s_le);
		}
	| expr_right EQ_OP expr_right
		{
			commands[sc_lvl - 1]->expr_stack.push_back(s_eq);
		}
	| expr_right NE_OP expr_right
		{
			commands[sc_lvl - 1]->expr_stack.push_back(s_ne);
		}
	| expr_right '+' expr_right
		{
			commands[sc_lvl - 1]->expr_stack.push_back(s_add);
		}
	| expr_right '-' expr_right
		{
			commands[sc_lvl - 1]->expr_stack.push_back(s_sub);
		}			
	| expr_right '*' expr_right
		{
			commands[sc_lvl - 1]->expr_stack.push_back(s_mul);
		}					
	| expr_right '/' expr_right
		{
			commands[sc_lvl - 1]->expr_stack.push_back(s_div);
		}
	| expr_right '%' expr_right
		{
			commands[sc_lvl - 1]->expr_stack.push_back(s_mod);	
		}
	| expr_right '|' expr_right
		{
			commands[sc_lvl - 1]->expr_stack.push_back(s_or);
		}	
	| expr_right '&' expr_right
		{
			commands[sc_lvl - 1]->expr_stack.push_back(s_and);	
		}
	| expr_right '^' expr_right
		{
			commands[sc_lvl - 1]->expr_stack.push_back(s_xor);	
		}
	| expr_right XOR expr_right
		{
			commands[sc_lvl - 1]->expr_stack.push_back(s_xor);	
		}		
	| expr_right '>' expr_right
		{
			commands[sc_lvl - 1]->expr_stack.push_back(s_g);
		}	
	| expr_right '<' expr_right
		{
			commands[sc_lvl - 1]->expr_stack.push_back(s_l);
		}
	| '-' expr_right %prec UMINUS
		{
			commands[sc_lvl - 1]->expr_stack.push_back(s_minus);
		}
	| '!' expr_right %prec UMINUS
		{
			commands[sc_lvl - 1]->expr_stack.push_back(s_no);
		}
	| NOT expr_right %prec UMINUS
		{
			commands[sc_lvl - 1]->expr_stack.push_back(s_no);
		}	
	| '(' expr_right ')'
	;

operation_s:
	operation
	{
		stdout_buf.clear();
	}
	;
	
operation:
	DELETE id_dotlist
		{
			s_command *s = new s_command;
			if (sc_lvl)
				s->parent = commands[sc_lvl - 1];
			s->comm = s_delete;
			s->buf = buf;
			if (sc_lvl == 0)
			{
				SVMachine::GetInstance()->AddCommand(s);
				SVMachine::GetInstance()->Execute();
			}
			else
			{
				CHECKEX
			}
			buf.clear();
		}
	| operation_extra
		{
			buf.clear();
			stdout_buf.clear();
		}
	| id_dotlist
		{
			s_command *s = new s_command;
			s->comm = s_operation;
			s->is_string = true;
			s->is_params = false;
			s->buf = buf;
			s->arg_type = arg_type;
			s->is_value = is_value;
			s->val_int = val_int;
			s->val_float = val_float;
			s->val_string = val_string;
			s->val_bool = val_bool;
			s->is_oper_with_params_now = false;
			s->is_expr_now = false;
			s->is_array_operation = false;
			s->is_array = false;
			s->is_hash_operation = false;
			if (sc_lvl == 0)
			{
				SVMachine::GetInstance()->AddCommand(s);
				SVMachine::GetInstance()->Execute();
			}
			else
			{
				s->parent = commands[sc_lvl - 1];
				s->is_array_operation = s->parent->is_array_operation;
				s->is_oper_with_params_now = s->parent->is_oper_with_params_now;
				CHECK
			}
			buf.clear();
		}
	;
		
operation_extra:
		operation_object '(' {
			s_command *s = new s_command;
			s->comm = s_operation;
			s->is_string = false;
			s->is_params = true;
			s->buf = buf;
			s->arg_type = arg_type;
			s->is_value = is_value;
			s->val_int = val_int;
			s->val_float = val_float;
			s->val_string = val_string;
			s->val_bool = val_bool;
			s->is_oper_with_params_now = true;
			s->is_expr_now = false;
			s->is_array_operation = false;
			s->is_array = false;
			s->is_hash_operation = false;
			s->value = is_this;
			is_this = false;
			commands[sc_lvl++] = s;
		} op_arg_list ')'
		{
			s_command *s = commands[--sc_lvl];
			if (sc_lvl == 0)
			{
				SVMachine::GetInstance()->AddCommand(s);
				SVMachine::GetInstance()->Execute();
			}
			else
			{
				CHECKEX
			}
			buf.clear();
			//args.clear();
			garbage.clear();
			buf.clear();
			op_param_cnt = 0;
			is_oper_with_params_now = false;
		}
	| operation_object '(' ')' 
		{
			s_command *s = new s_command;
			s->comm = s_operation;
			s->is_string = false;
			s->is_params = false;
			s->buf = buf;
			s->arg_type = arg_type;
			s->is_value = is_value;
			s->val_int = val_int;
			s->val_float = val_float;
			s->val_string = val_string;
			s->val_bool = val_bool;
			s->is_oper_with_params_now = false;
			s->is_expr_now = false;
			s->is_array_operation = false;
			s->is_array = false;
			s->is_hash_operation = false;
			s->value = is_this;
			is_this = false;
			if (sc_lvl == 0)
			{
				SVMachine::GetInstance()->AddCommand(s);
				SVMachine::GetInstance()->Execute();
			}
			else
			{
				s->parent = commands[sc_lvl - 1];
				s->is_array_operation = s->parent->is_array_operation;
				s->is_oper_with_params_now = s->parent->is_oper_with_params_now;	
				CHECK
			}
			buf.clear();
		}
		| id_dotlist { array_indx = -1; hash_key = ""; is_array_operation = true; is_ok_array = false; } '[' id_index ']'
		{
			s_command *s = new s_command;
			s->comm = s_operation;
			s->is_string = false;
			s->is_params = false;
			s->hash_key = hash_key;
			s->array_indx = array_indx;
			s->buf = buf;
			s->arg_type = arg_type;
			s->is_value = is_value;
			s->val_int = val_int;
			s->val_float = val_float;
			s->val_string = val_string;
			s->val_bool = val_bool;
			s->is_oper_with_params_now = false;
			s->is_expr_now = false;
			s->is_array_operation = is_array_operation;
			s->is_hash_operation = is_hash_operation;
			s->is_ok_array = false;
			s->is_array = true;
			if (sc_lvl == 0)
			{
				SVMachine::GetInstance()->AddCommand(s);
				SVMachine::GetInstance()->Execute();
			}
			else
			{
				s->parent = commands[sc_lvl - 1];
				s->is_array_operation = is_array_operation;;
				s->is_oper_with_params_now = is_oper_with_params_now;
				CHECK
			}
			buf.clear();
			is_array_operation = false;
			is_hash_operation = false;
		}
	;	
		
operation_object:
	id_dotlist
	| THIS {
		buf.push_back("this");
		is_this = true;
	} '.' id_dotlist
		
id_index:
	number
	| {is_oper_with_params_now = true;} id_parse_dotlist { is_oper_with_params_now = false; }
	| SOME_TEXT { hash_key = create_string((char*)$1); is_hash_operation = true; is_array_operation = false; }
	;
		
id_parse_dotlist:
	| id_dotlist INC_OP
		{
			id_parse_prepare(NUM_INC);
		}
	| id_dotlist DEC_OP
		{
			id_parse_prepare(NUM_DEC);
		}
	| id_dotlist
		{
			id_parse_prepare(NUM_NUM);
		}		
	;
		
op_arg_list:
	{op_param_cnt = 0; is_oper_with_params_now = true; } arg_list
	;
		
arg_list:
	arg_item
	| arg_list ',' arg_item
	;
	
arg_item:
	SOME_TEXT
	{ 
		arg_type = S_STRING; 
		val_string = create_string((char*)$1); 
		s_command *s = new s_command;
		s->comm = s_put;
		s->is_put_single_out = true;
		s->out = val_string;
		s->buf = buf;
		s->arg_type = arg_type;
		s->is_value = is_value;
		s->val_int = val_int;
		s->val_float = val_float;
		s->val_string = val_string;
		s->val_bool = val_bool;
		s->is_oper_with_params_now = false;
		s->is_expr_now = false;
		s->is_array_operation = false;
		s->is_array = false;
		s->is_hash_operation = false;
		if (sc_lvl == 0)
		{
			SVMachine::GetInstance()->AddCommand(s);
			SVMachine::GetInstance()->Execute();
		}
		else
		{
			CHECKEX
		}
		is_value = true;
	}
	| operation_extra
	{

	}
	| id_parse_dotlist
	| number
		{
			std::string ss = (char*)$1;
			add_integer();
			s_command *s = new s_command;
			s->comm = s_put;
			s->is_put_single_out = true;
			s->out = ss;
			s->buf = buf;
			s->arg_type = S_INT;
			s->is_value = is_value;
			s->val_int = val_int;
			s->val_float = val_float;
			s->val_string = val_string;
			s->val_bool = val_bool;
			s->is_oper_with_params_now = false;
			s->is_expr_now = false;
			s->is_array_operation = false;
			s->is_array = false;
			s->is_hash_operation = false;
			if (sc_lvl == 0)
			{
				SVMachine::GetInstance()->AddCommand(s);
				SVMachine::GetInstance()->Execute();
			}
			else
			{
				CHECKEX
			}
		}
	| FNUM
		{
			std::string ss = (char*)$1;
			s_command *s = new s_command;
			s->comm = s_put;
			s->is_put_single_out = true;
			s->out = ss;
			s->buf = buf;
			s->arg_type = S_FLOAT;
			s->is_value = is_value;
			s->val_int = val_int;
			s->val_float = val_float;
			s->val_string = val_string;
			s->val_bool = val_bool;
			s->is_oper_with_params_now = false;
			s->is_expr_now = false;
			s->is_array_operation = false;
			s->is_array = false;
			s->is_hash_operation = false;
			if (sc_lvl == 0)
			{
				SVMachine::GetInstance()->AddCommand(s);
				SVMachine::GetInstance()->Execute();
			}
			else
			{
				CHECKEX
			}
		}
	| BOOL
		{
			s_command *s = new s_command;
			s->comm = s_put;
			s->is_put_single_out = true;
			s->out = val_bool == true ? "true" : "false";
			s->buf = buf;
			s->arg_type = arg_type;
			s->is_value = is_value;
			s->val_int = val_int;
			s->val_float = val_float;
			s->val_string = val_string;
			s->val_bool = val_bool;
			s->is_oper_with_params_now = false;
			s->is_expr_now = false;
			s->is_array_operation = false;
			s->is_array = false;
			s->is_hash_operation = false;
			if (sc_lvl == 0)
			{
				SVMachine::GetInstance()->AddCommand(s);
				SVMachine::GetInstance()->Execute();
			}
			else
			{
				CHECKEX
			}
		}
	| VALUE
		{
			s_command *s = new s_command;
			s->comm = s_put;
			s->value = true;
			s->is_put_single_out = true;
			s->out = "";
			s->buf = buf;
			s->arg_type = S_VALUE;
			s->is_value = is_value;
			s->val_int = val_int;
			s->val_float = val_float;
			s->val_string = val_string;
			s->val_bool = val_bool;
			s->is_oper_with_params_now = false;
			s->is_expr_now = false;
			s->is_array_operation = false;
			s->is_array = false;
			s->is_hash_operation = false;
			if (sc_lvl == 0)
			{
				SVMachine::GetInstance()->AddCommand(s);
				SVMachine::GetInstance()->Execute();
			}
			else
			{
				CHECKEX
			}
		}
	;

put_s:
	PUT {
	
		s_command *s = new s_command;
		s->comm = s_put;
		s->buf = buf;
		s->is_oper_with_params_now = false;
		s->is_expr_now = false;
		s->is_array_operation = false;
		s->is_array = false;
		s->is_hash_operation = false;
		commands[sc_lvl++] = s;
			
	}	put_list
	{
		s_command *s = commands[--sc_lvl];
		if (!s)
			cerr << "epic fail!\n";
		if (sc_lvl == 0)
		{
			SVMachine::GetInstance()->AddCommand(s);
			SVMachine::GetInstance()->Execute();
		}
		else
		{
			CHECKEX
		}
	}
	;

put_list:
	arg_item
	| arg_item '+' put_list
	;

puts_s:
	PUTS  {
		s_command *s = new s_command;
		s->comm = s_puts;
		s->buf = buf;
		s->is_oper_with_params_now = false;
		s->is_expr_now = false;
		s->is_array_operation = false;
		s->is_array = false;
		s->is_hash_operation = false;
		commands[sc_lvl++] = s;
			
	}  put_list
	{
		s_command *s = commands[--sc_lvl];
		if (!s)
			cerr << "epic fail!\n";
		if (sc_lvl == 0)
		{
			SVMachine::GetInstance()->AddCommand(s);
			SVMachine::GetInstance()->Execute();
		}
		else
		{
			CHECKEX
		}
	}
	;

input_s:
	INPUT id_dotlist
	{
		s_command *s = new s_command;
		s->comm = s_input;
		s->buf = buf;
		s->is_oper_with_params_now = false;
		s->is_expr_now = false;
		s->is_array_operation = false;
		s->is_array = false;
		s->is_hash_operation = false;
		if (sc_lvl == 0)
		{
			SVMachine::GetInstance()->AddCommand(s);
			SVMachine::GetInstance()->Execute();
		}
		else
		{
			CHECKEX
		}
		buf.clear();
	}
	;

for_s:
	for_smpl
	| for_each
	;
	
for_smpl:
	FOR {
		s_command *s = new s_command;
		s->comm = s_for;
		s->buf = buf;
		s->is_oper_with_params_now = false;
		s->is_array_operation = false;
		s->is_array = false;
		s->is_hash_operation = false;
		s->expr_type = S_BOOL;
		commands[sc_lvl++] = s;
		s->is_array = false;
		buf.clear();
		s->is_expr_now = true;
	} '(' for_full ')' for_body {
		s_command *s = commands[--sc_lvl];
		if (!s)
			cerr << "epic fail!\n";
		if (sc_lvl == 0)
		{
			SVMachine::GetInstance()->AddCommand(s);
			SVMachine::GetInstance()->Execute();
		}
		else
		{
			CHECK
		}
		cerr << "for ok\n";
	}
	;

for_each:
	FOREACH {
		s_command *s = new s_command;
		s->comm = s_for;
		s->buf = buf;
		s->is_oper_with_params_now = false;
		s->is_array_operation = false;
		s->is_array = false;
		s->is_hash_operation = false;
		s->expr_type = S_BOOL;
		commands[sc_lvl++] = s;
		s->is_array = false;
		buf.clear();
		s->is_expr_now = true;
	} '(' for_in ')' for_body {
		s_command *s = commands[--sc_lvl];
		if (!s)
			cerr << "epic fail!\n";
		if (sc_lvl == 0)
		{
			SVMachine::GetInstance()->AddCommand(s);
			SVMachine::GetInstance()->Execute();
		}
		else
		{
			CHECK
		}
	}
	;

for_in:
	for_init IN for_collection { commands[sc_lvl - 1]->coll_id = buf; buf.clear(); }
	;

for_init:
	VAR ID
	{
		commands[sc_lvl - 1]->for_type = true;
		s_command *s = new s_command;
		s->obj_id = (char*)$2;
		s->comm = s_for;
		commands[sc_lvl - 1]->for_init = s;
		buf.clear();
	}
	;

for_collection:
	id_dotlist
	;

for_full:
{ is_for_init = true; } for_full_init { is_for_init = false; } ';'
		{ loops[loop_cnt++].if_expr = true; } for_expression { loops[loop_cnt-1].if_expr = false; } ';'
		{ loops[loop_cnt-1].if_alter = true; } for_step { loops[loop_cnt-1].if_alter = false; loop_cnt--; }
	;
	
for_full_init:
	var_asign_simple { cerr << "for init ok\n"; }
	;
	
for_expression:	
	expr_right
	;

for_step:	
	for_one_step
	| for_step ',' for_one_step
	;

for_one_step:
	expression
	| arg_item
	| operation
	| put_s
	| puts_s
	| input_s
	;
	
for_body:
	'{' {
			s_command *s = new s_command;
			s->comm = s_for_cont;
			s->buf = buf;
			commands[sc_lvl++] = s;
		} sentence_list '}' { 
			s_command *s = commands[--sc_lvl];
			s->parent = commands[sc_lvl - 1];
			if (sc_lvl == 0)
			{
				cerr << "error using block body! use only with 'for', 'while', 'if'.\n";
			}
			else
			{
				CHECK
			}
		}
	| sentence
	;
	
break_s:
	BREAK
		{
			s_command *s = new s_command;
			s->comm = s_break;
			CHECKEX
		}
	;

sentence_list:
	sentence
	| sentence_list sentence
	;
	
while_s:
	WHILE {
		s_command *s = new s_command;
		s->comm = s_while;
		s->buf = buf;
		s->is_oper_with_params_now = false;
		s->is_array_operation = false;
		s->is_array = false;
		s->is_hash_operation = false;
		s->expr_type = S_BOOL;
		commands[sc_lvl++] = s;
		s->is_array = false;
		buf.clear();
		s->is_expr_now = true;
	} '(' { loops[loop_cnt++].if_expr = true; } while_header ')' { loops[loop_cnt-1].if_expr = false; loop_cnt--; } for_body
	{
		s_command *s = commands[--sc_lvl];
		if (!s)
			cerr << "epic fail!\n";
		if (sc_lvl == 0)
		{
			SVMachine::GetInstance()->AddCommand(s);
			SVMachine::GetInstance()->Execute();
		}
		else
		{
			CHECK
		}
	}
	;

while_header:
	expr_right
	;
	
if_s:
	if_header
		{
			//cerr << "if end.\n";
			s_command *s = commands[--sc_lvl];
			if (!s)
				cerr << "epic fail!\n";
			if (sc_lvl == 0)
			{
				SVMachine::GetInstance()->AddCommand(s);
				SVMachine::GetInstance()->Execute();
			}
			else
			{
				//cerr << "add if to for_cont\n";
				CHECK
			}
			loop_cnt--;
		}
	| if_header ELSE { loop_cnt++; loops[loop_cnt-1].if_alter = true; loops[loop_cnt-1].if_expr = false;} for_body
		{
			//cerr << "if end.\n";
			s_command *s = commands[--sc_lvl];
			if (!s)
				cerr << "epic fail!\n";
			if (sc_lvl == 0)
			{
				SVMachine::GetInstance()->AddCommand(s);
				SVMachine::GetInstance()->Execute();
			}
			else
			{
				//cerr << "add if_else to for_cont\n";
				CHECK
			}
			loop_cnt--;
		}
	;

if_header:
	IF { 
		loops[loop_cnt++].if_alter = false;
		s_command *s = new s_command;
		s->comm = s_if;
		s->buf = buf;
		s->is_oper_with_params_now = false;
		s->is_array_operation = false;
		s->is_array = false;
		s->is_hash_operation = false;
		s->expr_type = S_BOOL;
		commands[sc_lvl++] = s;
		s->is_array = false;
		buf.clear();
		s->is_expr_now = true;
	} '(' { loops[loop_cnt-1].if_expr = true; } expr_right ')' { loops[loop_cnt-1].if_expr = false; loops[loop_cnt-1].if_alter = false; } for_body
	;
	
method_arg_list:
	| method_arg_list_item
	| method_arg_list ',' method_arg_list_item
	;
	
method_arg_list_item:
	type ID
	{
		if (sc_lvl && commands[sc_lvl - 1]->comm == s_method)
		{
			s_method_param *smp = new s_method_param;
			smp->type = arg_type;
			smp->id = (char*)$2;
			commands[sc_lvl - 1]->fparams.push_back(smp);
		}
		else
		{
			cerr << "error! use in method's declaration!.\n";
		}
	}		
	;
	
method_s:
	METHOD type '.' ID
	{
		s_command *s = new s_command;
		s->comm = s_method;
		s->out = (char*)$4;
		s->buf = buf;
		s->arg_type = arg_type;
		s->is_oper_with_params_now = false;
		s->is_array_operation = false;
		s->is_array = false;
		s->is_hash_operation = false;
		s->expr_type = S_BOOL;
		commands[sc_lvl++] = s;
		s->is_array = false;
		buf.clear();
		s->is_expr_now = true;
}'(' { is_new_method = true; } method_arg_list ')' { is_new_method = false; } for_body
	{
		//cerr << "method ok end\n";
		s_command *s = commands[--sc_lvl];

		if (!s)
			cerr << "epic fail!\n";
		if (sc_lvl == 0)
		{
			SVMachine::GetInstance()->AddCommand(s);
			SVMachine::GetInstance()->Execute();
		}
		else
		{
			CHECK
		}
	}
	;	
	
BOOL:
	BTRUE { val_bool = true; }
	| BFALSE { val_bool = false; }
	;
	
type:
	STRING { arg_type = S_STRING; is_value = false; }
	| INTEGER { arg_type = S_INT; is_value = false; }
	| FLOAT { arg_type = S_FLOAT; is_value = false; }
	| BOOLEAN { arg_type = S_BOOL; is_value = false; }
	| ARRAY { arg_type = S_ARRAY; is_value = false; }
	;
	
number:
	NUM { val_int = atoi((char*)$1); array_indx = val_int; }
	| '-' NUM { val_int = atoi((char*)$2) * (-1); }
	
array_type:
	STRING { arg_type_arr = S_STRING; }
	| INTEGER { arg_type_arr = S_INT; }
	| FLOAT { arg_type_arr = S_FLOAT; }
	| BOOLEAN { arg_type_arr = S_BOOL; }
	| ARRAY { arg_type_arr = S_ARRAY; }
	;
%%

void add_integer()
{
	int *val = new int;
	*val = val_int;
	s_param *sp = new s_param;
	sp->type = S_INT;
	sp->val = val;
	garbage.push_back(val);
}			

bool test_parent()
{
	return (commands[sc_lvl - 1]->comm == s_if || commands[sc_lvl - 1]->comm == s_while || commands[sc_lvl - 1]->comm == s_for || commands[sc_lvl - 1]->comm == s_method || (sc_lvl >= 2 && commands[sc_lvl - 1]->comm == s_for_cont && commands[sc_lvl - 2]->comm == s_while));
}

void make_float(char *s)
{
	val_float = atof(s);
}
			
void yyerror(char *s) {
   	fprintf(stderr, "%s\n", s);
	inin = noend = 0;
	yyparse();
}

std::string create_string(char *str)
{
	static char buf[255];
	register unsigned char i;
	for (i = 0; str[i] != '\0' && str[i] != '"' && i < 255; i++)
	{
		buf[i] = str[i];
	}
	buf[i] = '\0';
	std::string res = buf;
	return res;
}

void id_parse_prepare(num_act na)
{
	//cerr << "id_parse_prepare\n";
	if (sc_lvl)
	{
		//if (commands[sc_lvl - 1]->comm == s_put || commands[sc_lvl - 1]->comm == s_puts)
		//{
			s_command *s = new s_command;
			s->comm = s_put;
			s->is_id = true;
			s->na = na;
			s->buf = buf;
			s->arg_type = arg_type;
			s->is_value = is_value;
			s->val_int = val_int;
			s->val_float = s->val_float;
			s->val_string = s->val_string;
			s->val_bool = s->val_bool;
			s->is_oper_with_params_now = false;
			s->is_expr_now = commands[sc_lvl-1]->is_expr_now;
			s->is_array_operation = commands[sc_lvl-1]->is_array_operation;
			s->is_array = commands[sc_lvl-1]->is_array;
			s->is_hash_operation = commands[sc_lvl-1]->is_hash_operation;
			s->parent = commands[sc_lvl - 1];
			CHECK
			s->parent = commands[sc_lvl - 1];
			s->is_array_operation = s->parent->is_array_operation;
			s->is_oper_with_params_now = s->parent->is_oper_with_params_now;
	//	}
		//else if (commands[sc_lvl - 1]->comm == s_operation)
		//{
		//			
		//}
	}
	buf.clear();
}

int main( int argc, char *argv[] )
{
	int clen = 0;
	if ( argc == 2 )
	{
		yyin = fopen( argv[1], "r" );
		yyparse();
		return(1);
	}
	
	char *bufline = new char[8192];
	
	ind = 0;
	//cerr << "default size of command is " << sizeof(s_command) << endl;
	
	srand((unsigned int)time(0));
	
	char *line;
	
	while ( line = readline( (inin || noend) ? "... " : ">>> " ) )
	{
		char *expansion;
		int result;

		noend = 0;
		
		result = history_expand (line, &expansion);
		if (result)
			fprintf (stderr, "%s\n", expansion);

		if (result < 0 || result == 2)
		{
			free (expansion);
			continue;
		}

		add_history (expansion);
		strncpy (line, expansion, sizeof (line) - 1);
		free (expansion);

		strcat( &bufline[0], line );
		
		clen = strlen(line);
		
		if ( line[clen - 1] == '{' )
		{
			inin++;
		}
		else if ( line[clen - 1] == ';' || line[clen - 1] == '}' )
		{
			if ( line[clen - 1] == '}' )
			{
				inin--;
			}
			if ( inin )
				goto fix; // it's pity. =(
			
			yy_scan_string( &bufline[0] );
			yyparse();
			
			memset( (void*) &bufline[0], '\0', 8192 );
		}
		else if ( clen )
			noend = 1;
			
	fix:
		free( line );
		
	}
	
	delete bufline;
	cerr << "bye.\n";
	
	SVMachine::Release();
	return 0;
}
